package com.fisco.app.contract;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.v3.client.Client;
import org.fisco.bcos.sdk.v3.codec.datatypes.Bool;
import org.fisco.bcos.sdk.v3.codec.datatypes.Event;
import org.fisco.bcos.sdk.v3.codec.datatypes.Function;
import org.fisco.bcos.sdk.v3.codec.datatypes.Type;
import org.fisco.bcos.sdk.v3.codec.datatypes.TypeReference;
import org.fisco.bcos.sdk.v3.codec.datatypes.Utf8String;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.Int256;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.v3.contract.Contract;
import org.fisco.bcos.sdk.v3.crypto.CryptoSuite;
import org.fisco.bcos.sdk.v3.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.v3.model.CryptoType;
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class TestKV extends Contract {
    public static final String[] BINARY_ARRAY = {"60806040523480156200001157600080fd5b506110026000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b0e89adb6040518060400160405280600981526020017f706572736f6e5f6b7600000000000000000000000000000000000000000000008152506040518263ffffffff1660e01b8152600401620000e59190620003dc565b602060405180830381600087803b1580156200010057600080fd5b505af115801562000115573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200013b9190620002c7565b5060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f23f63c96040518060400160405280600981526020017f706572736f6e5f6b7600000000000000000000000000000000000000000000008152506040518263ffffffff1660e01b8152600401620001cf9190620003b8565b60206040518083038186803b158015620001e857600080fd5b505afa158015620001fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022391906200029b565b905080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505062000502565b6000815190506200027e81620004ce565b92915050565b6000815190506200029581620004e8565b92915050565b600060208284031215620002ae57600080fd5b6000620002be848285016200026d565b91505092915050565b600060208284031215620002da57600080fd5b6000620002ea8482850162000284565b91505092915050565b600062000300826200042a565b6200030c818562000435565b93506200031e81856020860162000487565b6200032981620004bd565b840191505092915050565b60006200034360048362000435565b91507f6e616d65000000000000000000000000000000000000000000000000000000006000830152602082019050919050565b60006200038560038362000435565b91507f61676500000000000000000000000000000000000000000000000000000000006000830152602082019050919050565b60006020820190508181036000830152620003d48184620002f3565b905092915050565b60006060820190508181036000830152620003f88184620002f3565b905081810360208301526200040d8162000334565b90508181036040830152620004228162000376565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000620004538262000467565b9050919050565b60008160030b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60005b83811015620004a75780820151818401526020810190506200048a565b83811115620004b7576000848401525b50505050565b6000601f19601f8301169050919050565b620004d98162000446565b8114620004e557600080fd5b50565b620004f3816200045a565b8114620004ff57600080fd5b50565b6106e680620005126000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461006c575b600080fd5b610055600480360381019061005091906103b3565b61009c565b6040516100639291906104c6565b60405180910390f35b610086600480360381019061008191906103f4565b61016c565b60405161009391906104f6565b60405180910390f35b6000606060008090506060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663693ec85e866040518263ffffffff1660e01b8152600401610102919061052c565b60006040518083038186803b15801561011a57600080fd5b505afa15801561012e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906101579190610336565b80925081935050508181935093505050915091565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e942b51685856040518363ffffffff1660e01b81526004016101cc92919061054e565b602060405180830381600087803b1580156101e657600080fd5b505af11580156101fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021e919061038a565b90507f0cf385eb927670d0229706269f568122463b7535b52bd98e52d4787771855d0d8160405161024f9190610511565b60405180910390a18060030b91505092915050565b60008151905061027381610682565b92915050565b60008151905061028881610699565b92915050565b600082601f83011261029f57600080fd5b81356102b26102ad826105b2565b610585565b915080825260208301602083018583830111156102ce57600080fd5b6102d983828461062f565b50505092915050565b600082601f8301126102f357600080fd5b8151610306610301826105b2565b610585565b9150808252602083016020830185838301111561032257600080fd5b61032d83828461063e565b50505092915050565b6000806040838503121561034957600080fd5b600061035785828601610264565b925050602083015167ffffffffffffffff81111561037457600080fd5b610380858286016102e2565b9150509250929050565b60006020828403121561039c57600080fd5b60006103aa84828501610279565b91505092915050565b6000602082840312156103c557600080fd5b600082013567ffffffffffffffff8111156103df57600080fd5b6103eb8482850161028e565b91505092915050565b6000806040838503121561040757600080fd5b600083013567ffffffffffffffff81111561042157600080fd5b61042d8582860161028e565b925050602083013567ffffffffffffffff81111561044a57600080fd5b6104568582860161028e565b9150509250929050565b610469816105fa565b82525050565b61047881610606565b82525050565b6104878161061d565b82525050565b6000610498826105de565b6104a281856105e9565b93506104b281856020860161063e565b6104bb81610671565b840191505092915050565b60006040820190506104db6000830185610460565b81810360208301526104ed818461048d565b90509392505050565b600060208201905061050b600083018461046f565b92915050565b6000602082019050610526600083018461047e565b92915050565b60006020820190508181036000830152610546818461048d565b905092915050565b60006040820190508181036000830152610568818561048d565b9050818103602083015261057c818461048d565b90509392505050565b6000604051905081810181811067ffffffffffffffff821117156105a857600080fd5b8060405250919050565b600067ffffffffffffffff8211156105c957600080fd5b601f19601f8301169050602081019050919050565b600081519050919050565b600082825260208201905092915050565b60008115159050919050565b6000819050919050565b60008160030b9050919050565b600061062882610610565b9050919050565b82818337600083830152505050565b60005b8381101561065c578082015181840152602081019050610641565b8381111561066b576000848401525b50505050565b6000601f19601f8301169050919050565b61068b816105fa565b811461069657600080fd5b50565b6106a281610610565b81146106ad57600080fd5b5056fea264697066735822122063d89a6d0d322afadc9fd722e6a30831754c101f363b779db1bafde0746cfebd64736f6c634300060a0033"};

    public static final String BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {"60806040523480156200001157600080fd5b506110026000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394558dab6040518060400160405280600981526020017f706572736f6e5f6b7600000000000000000000000000000000000000000000008152506040518263ffffffff1660e01b8152600401620000e59190620003dc565b602060405180830381600087803b1580156200010057600080fd5b505af115801562000115573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200013b9190620002c7565b5060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166359a48b656040518060400160405280600981526020017f706572736f6e5f6b7600000000000000000000000000000000000000000000008152506040518263ffffffff1660e01b8152600401620001cf9190620003b8565b60206040518083038186803b158015620001e857600080fd5b505afa158015620001fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022391906200029b565b905080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505062000502565b6000815190506200027e81620004ce565b92915050565b6000815190506200029581620004e8565b92915050565b600060208284031215620002ae57600080fd5b6000620002be848285016200026d565b91505092915050565b600060208284031215620002da57600080fd5b6000620002ea8482850162000284565b91505092915050565b600062000300826200042a565b6200030c818562000435565b93506200031e81856020860162000487565b6200032981620004bd565b840191505092915050565b60006200034360038362000435565b91507f61676500000000000000000000000000000000000000000000000000000000006000830152602082019050919050565b60006200038560048362000435565b91507f6e616d65000000000000000000000000000000000000000000000000000000006000830152602082019050919050565b60006020820190508181036000830152620003d48184620002f3565b905092915050565b60006060820190508181036000830152620003f88184620002f3565b905081810360208301526200040d8162000376565b90508181036040830152620004228162000334565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000620004538262000467565b9050919050565b60008160030b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60005b83811015620004a75780820151818401526020810190506200048a565b83811115620004b7576000848401525b50505050565b6000601f19601f8301169050919050565b620004d98162000446565b8114620004e557600080fd5b50565b620004f3816200045a565b8114620004ff57600080fd5b50565b6106e680620005126000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80631a391cb41461003b5780637b1b8e031461006b575b600080fd5b610055600480360381019061005091906103f4565b61009c565b60405161006291906104f6565b60405180910390f35b610085600480360381019061008091906103b3565b610194565b6040516100939291906104c6565b60405180910390f35b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631a391cb485856040518363ffffffff1660e01b81526004016100fc92919061054e565b602060405180830381600087803b15801561011657600080fd5b505af115801561012a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014e919061038a565b90507fc044934b9c0dc8f2e96c0797246bde787cfafd3e8474b4ac3271c1d3ac7b819a8160405161017f9190610511565b60405180910390a18060030b91505092915050565b6000606060008090506060600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637b1b8e03866040518263ffffffff1660e01b81526004016101fa919061052c565b60006040518083038186803b15801561021257600080fd5b505afa158015610226573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061024f9190610336565b80925081935050508181935093505050915091565b60008151905061027381610682565b92915050565b60008151905061028881610699565b92915050565b600082601f83011261029f57600080fd5b81356102b26102ad826105b2565b610585565b915080825260208301602083018583830111156102ce57600080fd5b6102d983828461062f565b50505092915050565b600082601f8301126102f357600080fd5b8151610306610301826105b2565b610585565b9150808252602083016020830185838301111561032257600080fd5b61032d83828461063e565b50505092915050565b6000806040838503121561034957600080fd5b600061035785828601610264565b925050602083015167ffffffffffffffff81111561037457600080fd5b610380858286016102e2565b9150509250929050565b60006020828403121561039c57600080fd5b60006103aa84828501610279565b91505092915050565b6000602082840312156103c557600080fd5b600082013567ffffffffffffffff8111156103df57600080fd5b6103eb8482850161028e565b91505092915050565b6000806040838503121561040757600080fd5b600083013567ffffffffffffffff81111561042157600080fd5b61042d8582860161028e565b925050602083013567ffffffffffffffff81111561044a57600080fd5b6104568582860161028e565b9150509250929050565b610469816105fa565b82525050565b61047881610606565b82525050565b6104878161061d565b82525050565b6000610498826105de565b6104a281856105e9565b93506104b281856020860161063e565b6104bb81610671565b840191505092915050565b60006040820190506104db6000830185610460565b81810360208301526104ed818461048d565b90509392505050565b600060208201905061050b600083018461046f565b92915050565b6000602082019050610526600083018461047e565b92915050565b60006020820190508181036000830152610546818461048d565b905092915050565b60006040820190508181036000830152610568818561048d565b9050818103602083015261057c818461048d565b90509392505050565b6000604051905081810181811067ffffffffffffffff821117156105a857600080fd5b8060405250919050565b600067ffffffffffffffff8211156105c957600080fd5b601f19601f8301169050602081019050919050565b600081519050919050565b600082825260208201905092915050565b60008115159050919050565b6000819050919050565b60008160030b9050919050565b600061062882610610565b9050919050565b82818337600083830152505050565b60005b8381101561065c578082015181840152602081019050610641565b8381111561066b576000848401525b50505050565b6000601f19601f8301169050919050565b61068b816105fa565b811461069657600080fd5b50565b6106a281610610565b81146106ad57600080fd5b5056fea264697066735822122077cf8e92be6d38d47b13851247d71c3302bf5c5df11ba29972dd160afd00969b64736f6c634300060a0033"};

    public static final String SM_BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"SetEvent\",\"type\":\"event\"},{\"conflictFields\":[{\"kind\":0}],\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"selector\":[1765722206,2065403395],\"stateMutability\":\"view\",\"type\":\"function\"},{\"conflictFields\":[{\"kind\":0}],\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"age\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"selector\":[3913463062,439950516],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_GET = "get";

    public static final String FUNC_SET = "set";

    public static final Event SETEVENT_EVENT = new Event("SetEvent", 
            Arrays.<TypeReference<?>>asList(new TypeReference<Int256>() {}));
    ;

    protected TestKV(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public static String getABI() {
        return ABI;
    }

    public List<SetEventEventResponse> getSetEventEvents(TransactionReceipt transactionReceipt) {
        List<EventValuesWithLog> valueList = extractEventParametersWithLog(SETEVENT_EVENT, transactionReceipt);
        ArrayList<SetEventEventResponse> responses = new ArrayList<SetEventEventResponse>(valueList.size());
        for (EventValuesWithLog eventValues : valueList) {
            SetEventEventResponse typedResponse = new SetEventEventResponse();
            typedResponse.log = eventValues.getLog();
            typedResponse.count = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue();
            responses.add(typedResponse);
        }
        return responses;
    }

    public Tuple2<Boolean, String> get(String name) throws ContractException {
        final Function function = new Function(FUNC_GET, 
                Arrays.<Type>asList(new Utf8String(name)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {}, new TypeReference<Utf8String>() {}));
        List<Type> results = executeCallWithMultipleValueReturn(function);
        return new Tuple2<Boolean, String>(
                (Boolean) results.get(0).getValue(), 
                (String) results.get(1).getValue());
    }

    public TransactionReceipt set(String name, String age) {
        final Function function = new Function(
                FUNC_SET, 
                Arrays.<Type>asList(new Utf8String(name),
                new Utf8String(age)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String set(String name, String age, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_SET, 
                Arrays.<Type>asList(new Utf8String(name),
                new Utf8String(age)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForSet(String name, String age) {
        final Function function = new Function(
                FUNC_SET, 
                Arrays.<Type>asList(new Utf8String(name),
                new Utf8String(age)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple2<String, String> getSetInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_SET, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Utf8String>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, String>(

                (String) results.get(0).getValue(), 
                (String) results.get(1).getValue()
                );
    }

    public Tuple1<BigInteger> getSetOutput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getOutput();
        final Function function = new Function(FUNC_SET, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Int256>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<BigInteger>(

                (BigInteger) results.get(0).getValue()
                );
    }

    public static TestKV load(String contractAddress, Client client, CryptoKeyPair credential) {
        return new TestKV(contractAddress, client, credential);
    }

    public static TestKV deploy(Client client, CryptoKeyPair credential) throws ContractException {
        return deploy(TestKV.class, client, credential, getBinary(client.getCryptoSuite()), getABI(), null, null);
    }

    public static class SetEventEventResponse {
        public TransactionReceipt.Logs log;

        public BigInteger count;
    }

    @Override
    public String toString() {
        return "TestKV{" +
                "contractAddress='" + contractAddress + '\'' +
                '}';
    }
}
